// MainDlg.cpp : implementation of the CMainDlg class
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h"
#include <atlstr.h>
#include <utility>

#include "aboutdlg.h"
#include "MainDlg.h"

#define Is_FileDot(strFileName) (0 == StrCmp(strFileName, _T(".")) || 0 == StrCmp(strFileName, _T("..")))

const CString g_c_strFileDirInitTxt = _T("Please select or input your path to search...");
const CString g_c_strName2ReplaceInitTxt = _T("Please input the word(s) to replace...");
const CString g_c_strNameReplaceWithInitTxt = _T("Please input the word(s) to replace with...");

typedef enum 
{
	enLstNum = 0x00,
	enLstStat,
	enLstOldPath,
	enLstNewPath
};


BOOL CMainDlg::PreTranslateMessage(MSG* pMsg)
{
	return CWindow::IsDialogMessage(pMsg);
}

BOOL CMainDlg::OnIdle()
{
	return FALSE;
}

LRESULT CMainDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	// center the dialog on the screen
	CenterWindow();

	// set icons
	HICON hIcon = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), 
		IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
	SetIcon(hIcon, TRUE);
	HICON hIconSmall = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), 
		IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
	SetIcon(hIconSmall, FALSE);

	// register object for message filtering and idle updates
	CMessageLoop* pLoop = _Module.GetMessageLoop();
	ATLASSERT(pLoop != NULL);
	pLoop->AddMessageFilter(this);
	pLoop->AddIdleHandler(this);

	UIAddChildWindowContainer(m_hWnd);

	m_editFileSourceDir.Attach(::GetDlgItem(m_hWnd, IDC_EDIT_FILE_DIR));
	m_editName2Replace.Attach(::GetDlgItem(m_hWnd, IDC_EDIT_NAME_2_REPLACE));
	m_editNameReplaceWith.Attach(::GetDlgItem(m_hWnd, IDC_EDIT_FILE_REPLACE_WITH));
	m_editFileSourceDir.SetWindowText(g_c_strFileDirInitTxt);
	m_editName2Replace.SetWindowText(g_c_strName2ReplaceInitTxt);
	m_editNameReplaceWith.SetWindowText(g_c_strNameReplaceWithInitTxt);

	m_lstMonitor.Attach(::GetDlgItem(m_hWnd, IDC_LIST_MONITOR));
	m_lstMonitor.ModifyStyle(0, LVS_SHOWSELALWAYS);
	DWORD dwType = ListView_GetExtendedListViewStyle(m_lstMonitor);
	ListView_SetExtendedListViewStyle(m_lstMonitor, dwType | LVS_EX_FULLROWSELECT);

	m_lstMonitor.InsertColumn(enLstNum, L"No.", LVCFMT_LEFT, 40);
	m_lstMonitor.InsertColumn(enLstStat, L"State", LVCFMT_LEFT, 40);
	m_lstMonitor.InsertColumn(enLstOldPath, L"Original", LVCFMT_LEFT, 300);
	m_lstMonitor.InsertColumn(enLstNewPath, L"NewFile", LVCFMT_LEFT, 300);

	CButton(::GetDlgItem(m_hWnd, ID_BTN_REPLACE_DO)).EnableWindow(FALSE);
	CButton(::GetDlgItem(m_hWnd, ID_BTN_REPLACE_READY)).EnableWindow(FALSE);
	return TRUE;
}

LRESULT CMainDlg::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	// unregister message filtering and idle updates
	CMessageLoop* pLoop = _Module.GetMessageLoop();
	ATLASSERT(pLoop != NULL);
	pLoop->RemoveMessageFilter(this);
	pLoop->RemoveIdleHandler(this);

	return 0;
}

LRESULT CMainDlg::OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	CAboutDlg dlg;
	dlg.DoModal();
	return 0;
}

LRESULT CMainDlg::OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	// TODO: Add validation code 
	CloseDialog(wID);
	return 0;
}

LRESULT CMainDlg::OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	CloseDialog(wID);
	return 0;
}

void CMainDlg::CloseDialog(int nVal)
{
	DestroyWindow();
	::PostQuitMessage(nVal);
}

int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)  
{
	if(uMsg == BFFM_INITIALIZED)
	{  
		SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
	}
	return 0;  
}


LRESULT CMainDlg::OnBnClickedSelectDir(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	BROWSEINFO bi = {};
	TCHAR Buffer[MAX_PATH] = {};
	bi.hwndOwner = NULL;
	bi.pidlRoot = NULL;
	bi.pszDisplayName = Buffer;
	bi.lpszTitle = L"Plese select your folder";
	bi.ulFlags = BIF_VALIDATE | BIF_EDITBOX | BIF_BROWSEINCLUDEURLS;
	bi.lpfn = NULL;
	bi.lParam = 0;
	bi.iImage = IDR_MAINFRAME;

	CString strLastPath;
	CButton(::GetDlgItem(m_hWnd, IDC_EDIT_FILE_DIR)).GetWindowText(strLastPath);
	if (PathFileExists(strLastPath))
	{
		bi.lParam = (long)(LPCTSTR)(strLastPath);
		bi.lpfn = BrowseCallbackProc;
	}

	LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);
	if(pIDList)
	{
		SHGetPathFromIDList(pIDList, Buffer);
		m_editFileSourceDir.SetWindowText(Buffer);
		if (PathFileExists(Buffer))
		{
			CButton(::GetDlgItem(m_hWnd, ID_BTN_REPLACE_READY)).EnableWindow(TRUE);
		}
	}

	return 0;
}

LRESULT CMainDlg::OnBnClickedBtnReplaceReady(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	do 
	{
		ClearData();
		FillNameInputInfo();
		if (!SecureCheck())
		{
			break;
		}

		RecursiveFindFile(m_strSourceDir);
		CButton(::GetDlgItem(m_hWnd, ID_BTN_REPLACE_DO)).EnableWindow(TRUE);

	} while (FALSE);
	return 0;
}

LRESULT CMainDlg::OnBnClickedBtnReplaceDo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND hWndCtl, BOOL& /*bHandled*/)
{
	int nItemCount = m_lstMonitor.GetItemCount();
	for (int i = 0; i < nItemCount; i++)
	{
		CString strOldPath;
		CString strNewPath;
		m_lstMonitor.GetItemText(i, enLstOldPath, strOldPath.GetBuffer(MAX_PATH), MAX_PATH);
		m_lstMonitor.GetItemText(i, enLstNewPath, strNewPath.GetBuffer(MAX_PATH), MAX_PATH);
		strOldPath.ReleaseBuffer();
		strNewPath.ReleaseBuffer();

		if (MoveFile(strOldPath, strNewPath))
		{
			m_lstMonitor.SetItemText(i, enLstStat, _T("Y"));
		}
		else
		{
			m_lstMonitor.SetItemText(i, enLstStat, _T("N"));
		}
	}

	CButton(hWndCtl).EnableWindow(FALSE);
	return 0;
}

LRESULT CMainDlg::OnEnChangeEditFileDir(WORD /*wNotifyCode*/, WORD /*wID*/, HWND hWndCtl, BOOL& /*bHandled*/)
{
	CString strFolder;
	CButton(hWndCtl).GetWindowText(strFolder);
	if (PathFileExists(strFolder))
	{
		CButton(::GetDlgItem(m_hWnd, ID_BTN_REPLACE_READY)).EnableWindow(TRUE);
	}
	else
	{
		CButton(::GetDlgItem(m_hWnd, ID_BTN_REPLACE_READY)).EnableWindow(FALSE);
	}
	return 0;
}

void CMainDlg::ClearData()
{
	m_mapFileMap.clear();
	m_mapFolderMap.clear();
	m_lstMonitor.DeleteAllItems();
}

void CMainDlg::FillNameInputInfo()
{
	m_editName2Replace.GetWindowText(m_strName2Replace);
	m_editNameReplaceWith.GetWindowText(m_strNameReplaceWith);
	m_editFileSourceDir.GetWindowText(m_strSourceDir);

	CButton btnRec;
	m_bIsRecursive = CButton(::GetDlgItem(m_hWnd, IDC_CHECK_RECURSIVE)).GetCheck();
	m_bIncludeDirName = CButton(::GetDlgItem(m_hWnd, IDC_CHECK_DIR_INCLUDE)).GetCheck();
}

BOOL CMainDlg::SecureCheck()
{
	//Check m_strName2Replace
	//check m_strNameReplaceWith
	//check m_strSourceDir
	return TRUE;
}

void CMainDlg::RecursiveFindFile(const CString& strPath)
{
	WIN32_FIND_DATA dataFind = {};
	HANDLE hFindFirst = FindFirstFile(strPath + "\\*.*", &dataFind);
	BOOL bFind = TRUE;

	while(INVALID_HANDLE_VALUE != hFindFirst && bFind)
	{
		bFind = FindNextFile(hFindFirst, &dataFind);
		if (bFind)
		{
			if (dataFind.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM
				|| dataFind.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN
				|| Is_FileDot(dataFind.cFileName))
			{
				continue;
			}

			if (dataFind.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			{
				if (m_bIncludeDirName)
				{
					CheckAddPath(strPath, dataFind.cFileName, enFolder);
				}

				if (m_bIsRecursive)
				{
					CString strFilePath(strPath);
					PathAppend(strFilePath.GetBuffer(MAX_PATH), dataFind.cFileName);
					strFilePath.ReleaseBuffer();
					RecursiveFindFile(strFilePath);
				}
				else
				{
					continue;
				}
			}
			else
			{
				if (CheckAddPath(strPath, dataFind.cFileName, enFile))
				{
					AddNewListItem(strPath, dataFind.cFileName, enFile);
				}
			}
		}
	}
	if (INVALID_HANDLE_VALUE != hFindFirst)
	{
		FindClose(hFindFirst);
		hFindFirst = INVALID_HANDLE_VALUE;
	}

	std::map<CString, CString>::iterator it = m_mapFolderMap.begin();
	for (; it != m_mapFolderMap.end(); it++)
	{
		//At last fill the folder to the list
		AddNewListItem(strPath, dataFind.cFileName, enFolder);
	}
}

BOOL CMainDlg::CheckAddPath( const CString& strFolder, const CString& strOldFileName, ENUM_FileType Type)
{
	BOOL bRet = FALSE;
	do 
	{
		int nPos = strOldFileName.Find(m_strName2Replace);
		if (-1 == nPos)
		{
			break;
		}

		CString strNewFileName(strOldFileName);
		strNewFileName.Replace(m_strName2Replace, m_strNameReplaceWith);

		CString strFilePathOld(strFolder);
		PathAppend(strFilePathOld.GetBuffer(MAX_PATH), strOldFileName);
		strFilePathOld.ReleaseBuffer();

		CString strFilePathNew(strFolder);
		PathAppend(strFilePathNew.GetBuffer(MAX_PATH), strNewFileName);
		strFilePathNew.ReleaseBuffer();

		if (enFile == Type)
		{
			m_mapFileMap.insert(std::make_pair<CString, CString>(strFilePathOld, strFilePathNew));
		}
		else if (enFolder == Type)
		{
			m_mapFolderMap.insert(std::make_pair<CString, CString>(strFilePathOld, strFilePathNew));
		}

		bRet = TRUE;
	} while (FALSE);
	
	return bRet;
}

void CMainDlg::AddNewListItem( const CString& strFolder, const CString& strileName, ENUM_FileType Type)
{
	do 
	{
		CString strFilePath(strFolder);
		PathAppend(strFilePath.GetBuffer(MAX_PATH), strileName);
		strFilePath.ReleaseBuffer();

		std::map<CString, CString>* pMapList = NULL;
		if (enFile == Type)
		{
			pMapList = &m_mapFileMap;
		}
		else if (enFolder == Type)
		{
			pMapList = &m_mapFolderMap;
		}

		if (!pMapList)
		{
			break;
		}


		std::map<CString, CString>::iterator it = pMapList->find(strFilePath);
		if (it != pMapList->end())
		{
			CString strNo;
			int nCount = m_lstMonitor.GetItemCount();
			strNo.Format(_T("%d"), nCount+1);
			m_lstMonitor.InsertItem(nCount, strNo);
			m_lstMonitor.SetItemText(nCount, 1, _T("N/A"));
			m_lstMonitor.SetItemText(nCount, 2, it->first);
			m_lstMonitor.SetItemText(nCount, 3, it->second);
		}
	} while (FALSE);
}

LRESULT CMainDlg::OnEditSetFocus( WORD /*wNotifyCode*/, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/ )
{
	switch(wID)
	{
	case IDC_EDIT_FILE_DIR:
		{
			CString strEdit;
			m_editFileSourceDir.GetWindowText(strEdit);
			if (0 == strEdit.Compare(g_c_strFileDirInitTxt))
			{
				m_editFileSourceDir.SetWindowText(_T(""));
			}
		}
		break;
	case IDC_EDIT_NAME_2_REPLACE:
		{
			CString strEdit;
			m_editName2Replace.GetWindowText(strEdit);
			if (0 == strEdit.Compare(g_c_strName2ReplaceInitTxt))
			{
				m_editName2Replace.SetWindowText(_T(""));
			}
		}
		break;
	case IDC_EDIT_FILE_REPLACE_WITH:
		{
			CString strEdit;
			m_editNameReplaceWith.GetWindowText(strEdit);
			if (0 == strEdit.Compare(g_c_strNameReplaceWithInitTxt))
			{
				m_editNameReplaceWith.SetWindowText(_T(""));
			}
		}
		break;
	default:
		break;
	}

	return S_OK;
}

LRESULT CMainDlg::OnEditKillFocus( WORD /*wNotifyCode*/, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/ )
{
	switch(wID)
	{
	case IDC_EDIT_FILE_DIR:
		{
			if (0 == m_editFileSourceDir.GetWindowTextLength())
			{
				m_editFileSourceDir.SetWindowText(g_c_strFileDirInitTxt);
			}
		}
		break;
	case IDC_EDIT_NAME_2_REPLACE:
		{
			if (0 == m_editName2Replace.GetWindowTextLength())
			{
				m_editName2Replace.SetWindowText(g_c_strName2ReplaceInitTxt);
			}
		}
		break;
	case IDC_EDIT_FILE_REPLACE_WITH:
		{
			if (0 == m_editNameReplaceWith.GetWindowTextLength())
			{
				m_editNameReplaceWith.SetWindowText(g_c_strNameReplaceWithInitTxt);
			}
		}
		break;
	default:
		break;
	}

	return S_OK;
}
